//----------------------------------------------------------------------------
// Copyright, 1991 .. 2001, by Mettler & Fuchs AG, Dietikon, Switzerland
//----------------------------------------------------------------------------
//
// Purpose:  Example Program 3 for RTX-51
//
//           Shows:  - task declaration with C language extensions
//                   - system startup
//                   - task creation
//                   - semaphore usage
//                   - task switching
//                   - problems resulting from round robin mechanisms
//
//                 Alter the ?RTX_TIMESHARING flag from 0 to 1 and vice versa
//                 within file RtxSetUp.INC, recompile the project and observe
//                 the different behaviour of the system.
//
//           This program is intended as an introduction to working with
//           RTX-51. Feel free to change it in any way helping you to
//           understand RTX-51 operation.
//
// File:     Example3.c
// Created:  1991 by --
// Modified: 2001-JUN-28 by P. Baessler
//
//----------------------------------------------------------------------------

// Includes ------------------------------------------------------------------

#include <Rtx51.h>


// Defines -------------------------------------------------------------------

//
// Common constants
//
#define  UPPER_LIMIT  0x7FFF / 3

//
// RTX constants
//
#define  RTX_DONE      0
#define  WAIT_FOREVER  0xFF
#define  NO_MESSAGE    0

//
// Task numbers
//
// These numbers are used in the task declaration and identify the task code
// for task creation.
//
#define  SCHEDULER_TASK  0  // Task number for the task scheduler task.
#define  TASK_ONE        1  // Task number for the first task acting on the
                            // shared variable.
#define  TASK_TWO        2  // Task number for the second task acting on the
                            // shared variable.

//
// Task priorities
//
#define  TASK_PRIORITY  0

//
// Semaphores
//
#define  READY_SEMAPHORE   8
#define  DONE_SEMAPHORE    9
#define  MUTEX_SEMAPHORE  10



// Shared global variable ---------------------------------------------------

int  SharedVariable = 0;


// Tasks --------------------------------------------------------------------

void  One (void) _task_ TASK_ONE _priority_ TASK_PRIORITY
//
// Purpose: This task does some operations on a counter, increments  it and
//          passes control to the next task, after having counted to the
//          maximum value.
//
{
   unsigned int  Index;
   signed char   RtxCompletion;
   signed char   Event;

   //
   // Increment the Shared Variable and perform some operations on it
   //
   for (Index = 0; Index < UPPER_LIMIT; Index++)
   {
      Event = os_wait (K_MBX + MUTEX_SEMAPHORE, WAIT_FOREVER, NO_MESSAGE);
      if (SEM_EVENT == Event)
      {
         SharedVariable = SharedVariable * 3;
         SharedVariable = SharedVariable / 3;
         SharedVariable++;
         RtxCompletion = os_send_token (MUTEX_SEMAPHORE);
      } // if
   } // for
   //
   // Signal to another waiting task that access is granted
   //
   RtxCompletion = os_send_token (READY_SEMAPHORE);
   //
   // Extinguish this task, because it is no longer needed.
   //
   RtxCompletion = os_delete_task (TASK_ONE);

} // One


void  Two (void) _task_ TASK_TWO _priority_ TASK_PRIORITY
//
// Purpose: This task does some operations on a counter, decrements it and
//          passes control to the next task, after having counted to the
//          minimum value.
//
{
   unsigned int  Index;
   signed char   RtxCompletion;
   signed char   Event;

   //
   // Increment the Shared Variable and perform some operations on it
   //
   for (Index = 0; Index < UPPER_LIMIT; Index++)
   {
      Event = os_wait (K_MBX + MUTEX_SEMAPHORE, WAIT_FOREVER, NO_MESSAGE);
      if (SEM_EVENT == Event)
      {
         SharedVariable = SharedVariable * 3;
         SharedVariable = SharedVariable / 3;
         SharedVariable--;
         RtxCompletion = os_send_token (MUTEX_SEMAPHORE);
      } // if
   } // for
   //
   // Signal to another waiting task that access is granted
   //
   RtxCompletion = os_send_token (READY_SEMAPHORE);
   //
   // Extinguish this task, because it is no longer needed.
   //
   RtxCompletion = os_delete_task (TASK_TWO);

   //
   // Just in case, the task could not be deleted.
   //
   for (;;);

} // Two


void  Scheduler (void) _task_ SCHEDULER_TASK _priority_ TASK_PRIORITY
//
// Purpose: This task starts the tasks acting on a shared variable and waits
//          afterwards for the termination of the tasks.
//
{
   unsigned char  RtxCompletion;

   RtxCompletion = os_send_token (MUTEX_SEMAPHORE);
   RtxCompletion = os_create_task (TASK_ONE);
   RtxCompletion = os_create_task (TASK_TWO);
   if (SEM_EVENT ==
       os_wait (K_MBX + READY_SEMAPHORE, WAIT_FOREVER, NO_MESSAGE))
   {
      //
      // The first task has finished, wait for the second
      //
      if (SEM_EVENT ==
          os_wait (K_MBX + READY_SEMAPHORE, WAIT_FOREVER, NO_MESSAGE))
      {
         for (;;); // Both tasks have finished.
      } // if
   } // if

   //
   // Analyse the value of SharedVariable, it should be zero if no racing
   // condition has occured.
   //
   os_delete_task (SCHEDULER_TASK);


} // Scheduler


void  main (void)
//
// Purpose: The main function, which gets executed after the start-up code.
//          It starts the first RTX task and will not return from the
//          os_start_system call provided the task was successfully started.
//
{
   signed char  RtxCompletion;   // RTX completion code


   //
   // Start the real-time system
   //
   RtxCompletion = os_start_system (SCHEDULER_TASK);

   //
   // The system could not get started or the memory pool creation failed,
   // when the program reaches here. Wait for doomsday.
   //
   for (;;);

} // main


